#ifndef INES_TYPE_H
#define INES_TYPE_H

#include "ines.h"


struct CPUPrivate {
    // A is byte-wide and along with the arithmetic logic unit (ALU), supports
    // using the status register for carrying, overflow detection, and so on.
    uint8 a;
    //X register
    uint8 x;
    // Y register
    uint8 y;
    // P has 6 bits used by the ALU but is byte-wide. PHP, PLP, arithmetic, testing, and
    // branch instructions can access this register. See status flags.
    uint8 p;
    // S is byte-wide and can be accessed using interrupts, pulls, pushes,
    // and transfers. It indexes into a 256-byte stack at $0100-$01FF.
    uint8 s;
    // The 2-byte program counter PC supports 65536 direct (unbanked) memory
    // locations, however not all values are sent to the cartridge. It can be
    // accessed either by allowing CPU's internal fetch logic increment the address
    // bus, an interrupt (NMI, Reset, IRQ/BRQ), and using the RTS/JMP/JSR/Branch
    // instructions.
    uint16 pc;
    //Should trigger reset interrupt?
    uint8 irq;
    //Extension cycle number
    uint8 cycle;
    //Already sync cycle
    uint8 synchronized;
    //CPU suspend cycle
    uint32 suspend;
};


struct NesConsolePrivate {
    CPU *cpu;
    PPU *ppu;
    MemBus *bus;
    //cartridge brand
    Mapper mapper;
    NesFormat format;
    NesRegion region;
    //Size of prg rom
    uint32 prgSize;
    //Size of chr rom
    uint32 chrSize;
    //Mirroring type
    Mirroring mirroring;
    uint8 *prgRom;
    uint8 *chrRom;
    InesGameCallback callback;
    //Cartridge mapper
    CartridgeMapper *cartridge;
    //Cpu master cycle
    volatile uint64 masterCycle;
};

struct MemBusPrivate {
    uint8 *ram;
    uint8 *sram;
    uint8 *expansion;
};

struct CartridgeMapperPrivate {
    /**
     * Cartridge mapper private instance
     */
    void *instance;

    /**
     * Get mapper name
     */
    String (*ines_mapper_name)();

    /**
     * Read a byte from prg-rom
     */
    uint8 (*ines_prg_read)(NesConsole *console, uint16 addr);

    /**
     * Read a byte from chr-rom
     */
    uint8 (*ines_chr_read)(NesConsole *console, uint16 addr);

    /**
     * Write a byte to prg-rom
     */
    void (*ines_prg_write)(NesConsole *console, uint16 addr, uint8 b);

    /**
     * Write a byte to chr-rom
     */
    void (*ines_chr_write)(NesConsole *console, uint16 addr, uint8 b);
};


struct PPUPrivate {
    //First or second write toggle (1 bit)
    uint8 w;
    //$2000(NMI enable (V), PPU master/slave (P), sprite height (H), background tile select (B),
    // sprite tile select (S), increment mode (I), nametable select (NN))
    uint8 control;
    //$2001(color emphasis (BGR), sprite enable (s), background enable (b), sprite left column enable
    // (M), background left column enable (m), greyscale (G))
    uint8 mask;
    //$2002(vblank (V), sprite 0 hit (S), sprite overflow (O); read resets write pair for $2005/$2006)
    uint8 status;
    //$2003 (OAM read/write address)
    uint8 oamAddr;
    //Fine X scroll (3 bits)
    uint8 x;
    //Temporary video address
    uint16 t;
    //Video address
    uint16 v;
    // Vide ram
    uint8 *vram;
    //PPU cycle
    uint16 cycle;
    uint8 readBuf;
    //even-odd flag
    bool oddFrame;
    //PPU Scanline
    uint16 scanline;
    //Palette
    uint8 *palette;
    //Primary OAM (holds 64 sprites for the frame)
    uint8 *primaryOam;
    //Secondary OAM (holds 8 sprites for the current scanline)
    uint8 *secondaryOam;
    uint8 tileIdx;
    uint8 tileAttr;
    uint8 lowerTile;
    uint8 upperTile;
    // 2 16-bit shift registers - These contain the pattern table data for two tiles. Every 8 cycles,
    // the data for the next tile is loaded into the upper 8 bits of this shift register. Meanwhile,
    // the pixel to render is fetched from one of the lower 8 bits.
    uint32 latchX32;
    //Store pixel in TV system palette index not real rgb value
    uint8 *pixelBuffer;
};

#endif //INES_TYPE_H
